# MakeBy: LiuBoyuan
from typing import Generic, TypeVar, Union, List, Dict

from fastapi.encoders import jsonable_encoder
from sqlalchemy.orm import Session

from Model import UserModel
from Schema.UserSchema import UserAddSchema, UserInfoSchema

RET = TypeVar('RET')
ADD = TypeVar("ADD")
MODEL = TypeVar("MODEL")


class BaseService(Generic[MODEL, RET, ADD]):
    def __init__(self, model, tablename, *, ret_schema=None, add_schema=None):
        self.model: MODEL = model
        self.tablename = tablename
        self.ret_schema: RET = ret_schema
        self.add_schema: ADD = add_schema

    def getById(self, id, db: Session):
        print(type(db))
        return db.query(self.model).filter(
            self.model.id == id
        ).first()

    def getByDict(self, userSchema, sisson: Session) -> RET:

        mapper = userSchema
        if not isinstance(userSchema, dict):
            mapper = userSchema.dict(exclude_unset=True)

        return sisson.query(self.model).filter_by(
            **mapper
        ).all()

    def add(self, schema: ADD, session: Session) -> None:
        json = jsonable_encoder(schema)
        model_instance: Union[UserModel, MODEL] = self.model(**json)
        session.add(model_instance)
        session.commit()

    def remove(self, schema: ADD, session: Session) -> None:
        """
        根据条件删除
        :param schema:
        :return:
        """
        schema: UserAddSchema = schema
        condition_mapper = schema.dict(exclude_unset=True)
        models: List[UserModel] = session.query(self.model).filter_by(
            **condition_mapper
        ).all()
        [session.delete(i) for i in models]
        session.commit()

    def update(self, sisson: Session, obj, id_name = None) -> None:
        id_name = "id" if id_name is None else id_name
        mapper = jsonable_encoder(obj)
        if not isinstance(mapper, dict):
            if id_name is None:
                id = mapper.id
            else:
                mapper:dict = mapper.dict()
                id = mapper.get(id_name)

            mapper = mapper.dict(exclude_unset=True)  # exclude_unset 会只保存设置了数据值的 字段
            print("->", mapper)
        else:
            id = mapper.get(id_name)
        # 获取需要修改的键值对

        intrinsical = self.getByDict({
            id_name: id
        }, sisson, )[0]  # 找到原有的对象

        assert intrinsical is not None, "数据不存在"
        for fieldname, value in mapper.items():
            print(intrinsical, fieldname,)
            if value is None:  # 该值并未进行更新
                continue
            setattr(intrinsical, fieldname, value)  # 对指定的对象的指定字段名设置对应的值

        sisson.commit()  # 因为会话层的数据和持久层的数据已经不一致了 所以这里可以做一个同步
        sisson.flush()


if __name__ == "__main__":
    userService: BaseService[UserModel, UserInfoSchema, UserAddSchema] = BaseService(UserModel, "user")
